package org.liziyi.pss.model.memory;

import org.liziyi.pss.common.enums.MemoryStatusEnum;
import org.liziyi.pss.config.Config;
import org.liziyi.pss.gui.MemoryGUI;
import org.liziyi.pss.model.Memory;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 采用首次适应分配法的内存
 *
 * @author liziyi
 */
public class FirstAdaptMemory implements Memory {
    private final MemoryGUI memoryGUI;
    /**
     * 存放空闲内存块
     */
    private List<int[]> memoryList;

    public FirstAdaptMemory() {
        memoryGUI = new MemoryGUI();
        init();
    }
    private void init(){
        // 初始化内存
        memoryList = new ArrayList<>(List.of(new int[]{Config.memorySysSize, Config.memoryTotalSize - 1}));
        refreshGUI(new int[]{0,Config.memorySysSize-1},MemoryStatusEnum.SYS_USED, "sys used");
        refreshGUI(new int[]{Config.memorySysSize,Config.memoryTotalSize-1},MemoryStatusEnum.FREE, "free");
    }
    @Override
    public synchronized int[] allocate(int size, int pid) {
        int[] ans = null, block;
        for (int i = 0; i < memoryList.size(); i++) {
            block = memoryList.get(i);
            // 该内存块不满足要求
            if (block[1] - block[0] + 1 < size) continue;
            ans = new int[]{block[0], block[0] + size - 1};
            block[0] += size;
            // 完全用完，直接删除
            if (block[0]>block[1]) {
                memoryList.remove(i);
            }
            refreshGUI(ans, MemoryStatusEnum.APPLICATION_USED, String.format("used by pid(%d)", pid));
            break;
        }
        return ans;
    }

    @Override
    public synchronized void free(int[] block) {
        int[] tmp;
        for (int i = 0; i < memoryList.size(); i++) {
            tmp = memoryList.get(i);
            if (tmp[1] + 1 < block[0]) continue;
            if (tmp[1] + 1 == block[0]) {
                if (i + 1 != memoryList.size() && block[1] + 1 == memoryList.get(i + 1)[0]) {
                    // 左右均合并
                    tmp[1] = memoryList.get(i + 1)[1];
                    memoryList.remove(i + 1);
                }else{
                    // 仅左合并
                    tmp[1] = block[1];
                }
                refreshGUI(block, MemoryStatusEnum.FREE, "free");
                return;
            }
            // 不涉及区间合并，在中间
            if (tmp[0] - 1 > block[1]) {
                memoryList.add(i, new int[]{block[0], block[1]});
                refreshGUI(block, MemoryStatusEnum.FREE, "free");
                return;
            }
            // 仅右合并
            if (tmp[0]-1==block[1]) {
                tmp[0] = block[0];
                refreshGUI(block, MemoryStatusEnum.FREE, "free");
                return;
            }
        }
        // 不涉及区间合并，在末尾
        memoryList.add(new int[]{block[0], block[1]});
        refreshGUI(block, MemoryStatusEnum.FREE, "free");
    }



    private void refreshGUI(int[] block, MemoryStatusEnum status, String msg) {
        Color color = switch (status) {
            case FREE -> new Color(175,255,170);
            case SYS_USED -> Color.GRAY;
            case APPLICATION_USED -> new Color(255,187,187);
        };
        SwingUtilities.invokeLater(() -> {
            // 投递到主事件循环中修改GUI
            for (int i = block[0]; i <= block[1]; i++) {
                memoryGUI.memoryJTable.getModel().setValueAt(new MemoryGUI.Cell(msg, color), i, 1);
            }
            memoryGUI.memoryJTable.repaint();
        });
    }
    @Override
    public void reset() {
        init();
    }
    public MemoryGUI getMemoryGUI() {
        return memoryGUI;
    }
}
